﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Reflection;
using System.Text.RegularExpressions;

namespace Pro.Common.IoC
{
    public class AssemblySourceBuilder : IAssemblySourceBuilder
    {
        public static readonly Regex ExcludeAssembliesRegex =
            new Regex(
                "^AjaxControlToolkit|^Antlr3|^Castle|^Common.Logging|^ComponentArt|^CppCodeProvider|^DataAnnotationsExtensions|^DotNetOpenAuth|^EntityFramework|^ExpressionSerialization|^Iesi|^log4net|^Lucene.Net|^MbUnit|^Microsoft|^Mono.Math|^mscorlib|^MvcContrib|^MvcSiteMapProvider|^Newtonsoft.Json|^NHibernate|^nsoftware.InPayWeb|^nunit|^Omu.ValueInjecter|^Org.Mentalis.Security.Cryptography|^PlainElastic.Net|^Quartz|^QuickGraph|^Recaptcha|^Remotion|^RestSharp|^Rhino|^SendGridMail|^System|^Telerik|^TestDriven|^TestFu|^Unity.WebApi|^VirtoCommerce|^VJSharpCodeProvider|^WebActivatorEx|^WebDev|^WebGrease",
                RegexOptions.IgnoreCase | RegexOptions.Compiled);

        private readonly IList<Assembly> _assemblies;

        public AssemblySourceBuilder()
        {
            _assemblies = new List<Assembly>();
        }

        #region IAssemblySourceBuilder Members

        public void IncludeAssembliesInBaseDirectory()
        {
            IncludeAssembliesInBaseDirectory(assembly => true);
        }

        public void IncludeAssembliesInBaseDirectory(Predicate<Assembly> predicate)
        {
            IncludeAssembliesInDirectory(AppDomain.CurrentDomain.BaseDirectory, predicate);
            IncludeAssembliesInDirectory(AppDomain.CurrentDomain.SetupInformation.PrivateBinPath, predicate);
        }

        public void IncludeAssembliesInDirectory(string path)
        {
            IncludeAssembliesInDirectory(path, assembly => true);
        }

        public void IncludeAssembliesInDirectory(string path, Predicate<Assembly> predicate)
        {
            if (!Directory.Exists(path))
            {
                return;
            }

            string[] assemblyFilePaths = Directory.GetFiles(path, "*.dll");
            foreach (string assemblyFilePath in assemblyFilePaths)
            {
                Assembly assembly = null;
                try
                {
                    assembly = Assembly.LoadFrom(assemblyFilePath);
                }
                catch
                {
                }

                if (assembly != null && predicate(assembly))
                {
                    IncludeAssembly(assembly);
                }
            }
        }

        public void IncludeAssembly(Assembly assembly)
        {
            if (!_assemblies.Contains(assembly))
            {
                _assemblies.Add(assembly);
            }
        }

        public IAssemblySource Build()
        {
            return new AssemblySource(_assemblies);
        }

        #endregion
    }
}